
#ifdef DEBUG
 #include "tbb/tick_count.h"
#endif /* DEBUG */
#include "common.h"

#include <iostream>
#include <fstream>

#include "Globals.h"
#include "ReferenceSequence.h"
#include "InputSequences.h"
#include "Job.h"
#include "DiagStretch.h"
#include "ThreadsPool.h"

///#include "tbb/task_scheduler_init.h"


/******* Definitions **************************/

/******* Data Types ***************************/

/******* Functions ****************************/


int main(int argc, char* argv[])
{
	/* read the configuration parameters */
	// first command line argument : number of threads
	size_t maxThreads = atol(argv[1]);

///	tbb::task_scheduler_init tbb_init(maxThreads);

	// second command line argument : window size
	minMatchLength = atol(argv[2]);
	
	// third command line argument : reference sequence file
#ifdef DEBUG
	tbb::tick_count t0 = tbb::tick_count::now();
#endif /* DEBUG */
	ifstream refSeqFile(argv[3], ios::in);
	refSeqFile.seekg(0, std::ios::end);
	streampos refSeqFileLength = refSeqFile.tellg();
	refSeqFile.seekg(0, std::ios::beg);
	refSeq = new ReferenceSequence(refSeqFile, refSeqFileLength);

#ifdef DEBUG
	cout << "Read reference sequence file in (seconds) " << ((tbb::tick_count::now() - t0).seconds()) << endl;
	refSeq->print();
#endif /* DEBUG */

	/* Initialize threads */
	pool = new ThreadsPool(maxThreads - 1);
	
	/* this is temporary solution for storing and sorting the results */
	myDoneJobs = new vector<vector<Job*>>(maxThreads, vector<Job*>());


	/* Read input file, and start running threads when an input is ready */
	// fourth command line argument and on : input sequences files
	for (uint i = 0; i < (argc - 4); i++)
	{
#ifdef DEBUG
		t0 = tbb::tick_count::now();
#endif /* DEBUG */
		ifstream inputFile(argv[4 + i], ios::in);
		inSeqsSeq.push_back(InputSequences(&inputFile));
#ifdef DEBUG
		cout << "Input file " << argv[4 + i] << " was read in (seconds) " << ((tbb::tick_count::now() - t0).seconds()) << endl;
		t0 = tbb::tick_count::now();
#endif /* DEBUG */


		
		Job *newJob = new Job(FILE_READ, i);
		newJob->process();
///		Job *newJob = new( tbb::task::allocate_root() ) Job(FILE_READ, i);
///		tbb::task::enqueue(*newJob);
	}
	
	pool->noMoreJobs();
	
#ifdef DEBUG
	for (uint i = 0; i < (argc - 4); i++)
		inSeqsSeq[i].print();
#endif /* DEBUG */

///#ifdef ADI_OLD
	/* Process main thread's work until a NULL job arrives */
	JobsQueue& mainsQueue = pool->getMainThreadQueue();
	
	while (true)
	{
		/* TODO - if we want to add stealing, the waiting should be timed out, and then trying to fetch from another queue */
		/* Wait for a job in the queue */
		Job *curJob = mainsQueue.waitForJob();

		if (curJob == NULL)
		{
#ifdef  DEBUG
			cout << "Main thread stops execution" << endl;
#endif  /* DEBUG */
			break;
		}

#ifdef  DEBUG
		cout << "Main thread processes a job of type = " << curJob->getType() << endl;
#endif  /* DEBUG */
		/* Process the job */
		curJob->process();
#ifdef  DEBUG
		cout << "Main thread finished processing job" << endl;
#endif  /* DEBUG */
		(*myDoneJobs)[0].push_back(curJob);
	}


	pool->stopThreads();

///#endif /* ADI_OLD */

	/* Wait for the threads to finish */
	
	/* TODO - Stopped here!!! */

	for (vector<vector<Job*>>::iterator it1=(*myDoneJobs).begin(); it1 < (*myDoneJobs).end(); it1++)
		for (vector<Job*>::iterator it=it1->begin() ; it < it1->end(); it++)
		{
			Job *curJob = *it;
			cout << inSeqsSeq[curJob->getInputFileIndx()].getSequence(curJob->getSeqInFile()).getName() << endl;
			for (vector<Match>::const_iterator it = curJob->getMatches().begin(); it < curJob->getMatches().end(); it++)
				it->print();

			delete curJob;
		}

	
	delete refSeq;

	return 0;
}


